home *** CD-ROM | disk | FTP | other *** search
- /*
- * This is the driver. A description of the driver can be found
- * in the Device Manager chapter of Inside Macintosh, and a
- * description of THIS driver can be found in the Print Manager
- * chapter.
- */
- /*
- * This file is part of the DMP-110 printer driver for the Macintosh
- * series of computers.
- */
- /*
- * Earle R. Horton.
- * Wednesday, November 30, 1988
- * All rights reserved.
- */
- #define DRIVER
- #include <Windows.h>
- #include <Events.h>
- #include <Dialogs.h>
- #include <Fonts.h>
- #include <Memory.h>
- #include <Resources.h>
- #include <ToolUtils.h>
- #include <Errors.h>
- #include <Desk.h>
- #include "dmp-110.h"
- #include "compat.h"
-
- #define __SEG__ Main
-
- #define lPrEvtAll 0x00FFFFFD
- #define lPrEvtTop 0x00FEFFFD
- #define dNeedGoodBye 4
-
- int checkabort();
-
- /* Useful constants */
- #define SERRESET 8
- #define SERSHAKE 10
-
- #define XONCR ((char)17)
- #define XOFFCR ((char)19)
- #define RESFILEID (-8192)
-
- extern char AOutName[],BOutName[];
- extern short BaudRates[];
- extern char prlfstr[];
- extern char prinitstr[];
- extern char prtopstr[];
- extern char preopstr[];
- extern char prmargin[];
- extern char prhireslf[];
-
- OSErr openprinterfile(),SPOpen();
- /*
- * Driver close routine.
- * Close serial port. Dispose of our storage.
- * Better not close the serial driver if we
- * are dealing with 64k ROMs.
- *
- * Called by device manager under UniFinder when application
- * heap is reinitialized.
- */
- OSErr myPrClose(p,d) /* Device Close Call */
- PrParam *p; /* ==> parameter block */
- DCtlPtr d; /* ==> device control entry */
- {
- return(noErr);
- }
- #include <strings.h>
- /*
- * Printer driver open routine. Open our printer resource file, get
- * any information we have stored there, allocate a non-relocatable
- * block of storage, set up a serial port for use. Check errors.
- */
- OSErr myPrOpen(p,d)
- PrParam *p; /* ==> parameter block */
- DCtlPtr d; /* ==> device control entry */
- {
- extern short DriverEntry;
- return (noErr);
- }
- OSErr myPrPrime(p,d) /* We don't do prime. It's for drivers which do */
- /* read/write directly. */
- PrParam *p; /* ==> parameter block */
- DCtlPtr d; /* ==> device control entry */
- {
- return(noErr);
- }
- OSErr myPrControl(p,d) /* Control calls. Many defined, few implemented. */
- PrParam *p; /* ==> parameter block */
- DCtlPtr d; /* ==> device control entry */
- {
- Dstorage storage;
- char *buf = nil;
- SysEnvRec World;
- OSErr error;
- ProcPtr idle;
-
- SysEnvirons(1,&World);
-
- PrSetError(noErr);
-
- memset(&storage,0,sizeof(Dstorage));
-
- error = SPOpen(&storage,&World);
- if(error != noErr) return noErr;
-
- storage.iopb.ioParam.ioResult = noErr;
- if(setjmp(storage.abortbuf) != 0){
- PBClose(&storage.iopb);
- if(p->csCode == iPrEvtCtl){
- DisposPtr(buf);
- }
- return noErr;
- }
- /*
- * Device Control Call. p->csCode gives opcode, and we switch on it
- * to perform low-level Printing calls
- */
- switch (p->csCode){
-
-
- case iPrBitsCtl: /* Send a bitmap to the printer. */
- break;
- case iPrEvtCtl: /* Screen printing. (cmd-shift 4.)*/
- if(*(short*)(&p->lParam1) == 1){ /* Top window. */
- buf = NewPtr(2000L);
- if(buf != nil){
- dumptop(&storage,buf);
- DisposPtr(buf);
- }
- }
- else if(*(short*)(&p->lParam1) == 2){ /* Screen. */
- buf = NewPtr(2000L);
- if(buf != nil){
- dumpscreen(&storage,buf);
- DisposPtr(buf);
- }
- }
- break;
- default:
- break;
- }
- PBClose(&storage.iopb);
- return noErr;
- }
- /*
- * Printer driver status call, used by the Font Manager to request
- * a copy of the printer's font characterization table. Ignored
- * like the control call.
- */
- OSErr myPrStatus(p,d) /* Device Status Call */
- PrParam *p; /* ==> parameter block */
- DCtlPtr d; /* ==> device control entry */
- {
- return (noErr);
- }
- /*
- * Open the serial driver and configure it. Quit if ioResult field
- * of parameter block ever becomes other than noErr.
- */
- OSErr SPOpen(s,World)
-
- register DPstorage s;
- SysEnvRec *World;
- {
- register ParmBlkPtr pb;
- int serconfig;
- Pfg settings;
- Handle pfilename;
- short pfile;
- pfilename = GetResource('STR ',0xE000);
- if(pfilename == nil){
- return ResError();
- }
- HLock(pfilename);
- pfile = OpenResFile(*pfilename);
- if(pfile == -1){
- return ResError();
- }
- DisposHandle(pfilename);
- settings = (Pfg)(GetResource('HEXA',RESFILEID));
- if(settings == nil){
- return ResError();
- }
- LoadResource(settings);
- HNoPurge(settings);
- pb = &s->iopb;
- switch (pport){ /* get the correct port */
- case 0: /* modem port */
- pb->ioParam.ioNamePtr = (StringPtr)AOutName;
- break;
- case 1: /* printer port */
- default:
- if(IsMPPOpen()){
- (void)StopAlert(ATALKALERT,nil);
- return portInUse;
- }
- pb->ioParam.ioNamePtr = (StringPtr)BOutName;
- break;
- }
- PBOpen(pb,FALSE);
- if (pb->ioParam.ioResult != noErr){
- return(pb->ioParam.ioResult);
- }
- pb->ioParam.ioNamePtr = nil;
- /*
- * Set up the io parameter block for writing to the serial driver.
- * a control call resets the baud rate
- */
- ((CntrlParam *)pb)->csCode = SERRESET;
- serconfig = data8 + noParity + stop20;
- serconfig += BaudRates[pbaud];
- ((CntrlParam*)pb)->csParam[0] = serconfig;
- PBControl(pb,FALSE);
- if (pb->ioParam.ioResult != noErr) return(pb->ioParam.ioResult);
- #define shake ((SerShk *)&((CntrlParam*)pb)->csParam[0])
- shake->errs = FALSE;
- shake->evts = FALSE;
- shake->fDTR = FALSE;
- shake->fInX = FALSE;
- if(XonXoff && (World->machineType >= envMachUnknown)){
- shake->fXOn = TRUE;
- shake->fCTS = FALSE;
- shake->xOn = XONCR;
- shake->xOff = XOFFCR;
- }
- else {
- shake->fXOn = FALSE;
- shake->fCTS = TRUE;
- }
- ((CntrlParam *)pb)->csCode = SERSHAKE;
- PBControl(pb,FALSE);
- if (pb->ioParam.ioResult != noErr) return(pb->ioParam.ioResult);
-
- pb->ioParam.ioPosMode = 0;
- pb->ioParam.ioPosOffset = 0;
- return(noErr);
- }
- printstring(s,string) /* Send a printer control string to the */
- /* serial driver. */
- register DPstorage s;
- unsigned char *string;
- {
- s->iopb.ioParam.ioBuffer = (Ptr)(string+1);
- s->iopb.ioParam.ioReqCount = (long)(string[0]);
- asyncwrite(s,checkabort);
- }
- /*
- * dumptop() - Called to dump the top window to the screen. Nothing if
- * top window is a color window.
- *
- * Uses PtInRgn() to determine the extent of the window's structure region,
- * so we can print the entire window frame. If you know of a better way,
- * let me know. Question: What do we do if we get a round window?
- */
- dumptop(s,obuf)
- DPstorage s;
- short *obuf;
- {
- EventRecord myevent;
- GrafPtr tmpport,oldport;
- int i,rows,width,first_row,last_row,left_offset;
- Rect printrect;
- GetPort(&oldport);
- tmpport = (GrafPtr)FrontWindow();
- SetPort(tmpport);
- /*
- * Expand portRect to Rect enclosing Window structure region.
- */
- printrect = tmpport->portRect;
- LocalToGlobal(&printrect);
- LocalToGlobal(&printrect.bottom);
- while(PtInRgn(*(Point*)(&printrect),((WindowPeek)tmpport)->strucRgn)){
- printrect.left--;
- }
- printrect.left++;
- while(PtInRgn(*(Point*)(&printrect),((WindowPeek)tmpport)->strucRgn)){
- printrect.top--;
- }
- printrect.top++;
- while(PtInRgn(*(Point*)(&printrect.bottom),((WindowPeek)tmpport)->strucRgn)){
- printrect.bottom++;
- }
- printrect.bottom--;
- while(PtInRgn(*(Point*)(&printrect.bottom),((WindowPeek)tmpport)->strucRgn)){
- printrect.right++;
- }
- printrect.right--;
- GlobalToLocal(&printrect);
- GlobalToLocal(&printrect.bottom);
- /*
- * Calculate rows in BitMap which we need to print. Send sixteen at a
- * time to the BitMap printing routine.
- */
- first_row = printrect.top - tmpport->portBits.bounds.top;
- last_row = printrect.bottom - tmpport->portBits.bounds.top;
- left_offset = printrect.left - tmpport->portBits.bounds.left;
- width = printrect.right - printrect.left;
- for(i=first_row;i<=last_row;i+=16){
- bitmap_to_hires(s,&tmpport->portBits,i,
- obuf,width,left_offset,last_row-i+1);
- }
- SetPort(oldport);
- }
- /*
- * dumpscreen() - Called to dump the screen to the printer. Dumps the
- * WMgrPort instead. Funky stuff if screen is not in two-color mode.
- */
- dumpscreen(s,obuf)
- DPstorage s;
- short *obuf;
- {
- GrafPtr tmpport;
- int i,rows,width;
- GetWMgrPort(&tmpport);
- rows = tmpport->portBits.bounds.bottom - tmpport->portBits.bounds.top;
- width = tmpport->portRect.right - tmpport->portRect.left - 1;
- for(i=0;i<=rows;i+=16){
- bitmap_to_hires(s,&tmpport->portBits,i,obuf,width,0,rows-i);
- }
- }
- /*
- * bitmap_to_hires()
- * This function translates a QuickDraw BitMap to codes which may
- * be sent to a Tandy DMP-110 dot-matrix printer in high-resolution
- * graphics mode. Graphics codes for this printer in hi-res mode
- * include all eight bit characters. There are two characters for each
- * column of 16 dots on the paper. The top dot (1) corresponds to bit
- * zero of the first byte sent. The bottom dot (16) corresponds to bit
- * eight of the second byte. There are 960 columns, or 1920 bytes, of
- * graphics data to be sent for one line of graphics output.
- * Note that the ToolBox bit manipulation routines use lower-to-upper
- * bit order.
- *
- * No smarts in this routine, the whole 1918 bytes are sent for each
- * line.
- */
-
- bitmap_to_hires(s,b,row,obuf,width,left_offset,nleft)
- DPstorage s; /* Global driver storage. */
- BitMap *b; /* BitMap to print. */
- int row; /* Starting row on this pass. */
- short *obuf; /* Serial port output buffer. */
- int width; /* Print this many columns. */
- int left_offset; /* Start this far from left of b->bounds.left. */
- int nleft; /* Max number of rows to print. */
- {
- short *obytes,*inbytes;
- int column,lastcol,nbits,dot;
-
- for(dot=960;dot-- >0;){
- obuf[dot] = 0;
- }
- obytes = obuf;
- lastcol = (b->bounds.right > 959) ? 959 : b->bounds.right;
- lastcol = (lastcol > width) ? width : lastcol;
- inbytes = (short *)(b->baseAddr + b->rowBytes*row);
- nbits = b->rowBytes*8;
- /*
- * Transform QuickDraw BitMap to Tandy DMP-110 high resolution graphics
- * using ToolBox bit-manipulation routines. Sixteen rows of BitMap
- * at column become two-byte printing code.
- */
- for(column=left_offset;column<=lastcol+left_offset;column++){
- for(dot=0;dot<8 && dot<nleft;dot++){
- if(BitTst(inbytes,(long)(column+dot*nbits))){
- BitSet(obytes,(long)(7-dot));
- }
- }
- for(dot=8;dot<16 && dot < nleft;dot++){
- if(BitTst(inbytes,(long)(column+dot*nbits))){
- BitSet(obytes,(long)(23-dot));
- }
- }
- obytes++;
- }
- output_hires_data(s,obuf,(long)(lastcol)-1); /* Send to printer. */
- }
- /*
- * output_hires_data() - Send a stream of high resolution graphics data
- * to the Tandy DMP-110. The codes for transferring the graphics, and
- * for the high-resolution paper advance, are hard-coded into this
- * routine. Skips blank graphics codes, and repositions the printer
- * head. The overhead is 8 bytes for repositioning the head and restarting
- * high resolution graphics. If there are four blank columns, then, we
- * break even. If there are more, we win. If there are less than four
- * blank columns, we lose.
- */
- output_hires_data(s,buf,columns)
- DPstorage s;
- short *buf;
- long columns;
- {
-
- short *p;
- short pos,ncodes,start,max;
- max = (columns > 959) ? 959 : columns;
- for(pos=0,ncodes=0,p=buf,start=0;pos<=columns;pos++){
- if(buf[pos] == 0){
- if(ncodes != 0){
- sendcodes(s,p,ncodes,start);
- ncodes = 0;
- }
- }else{
- if(ncodes == 0){
- p = &buf[pos];
- start = pos;
- }
- ncodes++;
- }
- }
- if(ncodes != 0){
- sendcodes(s,p,ncodes,start);
- }
- printstring(s,prhireslf);
- }
- sendcodes(s,buf,n,pos)
- DPstorage s;
- char *buf;
- int n,pos;
- {
- unsigned char codes[10];
- s->iopb.ioParam.ioBuffer = (Ptr)&codes[0];
- codes[0] = 27;
- codes[1] = 16;
- codes[2] = (pos>>8)&3;
- codes[3] = pos & 0xFF;
- codes[4] = 27;
- codes[5] = 73;
- codes[6] = (n>>8)&3;
- codes[7] = n&0xFF;
- s->iopb.ioParam.ioReqCount = 8;
- asyncwrite(s,checkabort); /* Send 8 bytes to printer. */
- s->iopb.ioParam.ioBuffer = &buf[0];
- s->iopb.ioParam.ioReqCount = 2*n;
- asyncwrite(s,checkabort); /* Print the buffer. */
- }
-
- /*
- * checkabort() - Returns TRUE if command-'.' detected. Otherwise,
- * FALSE.
- */
- checkabort()
- {
- EventRecord myevent;
- if(WaitNextEvent(everyEvent,&myevent,0L/*WaitTime*/,0L)){
- if(LoWord(myevent.message & charCodeMask) == '.' &&
- (myevent.modifiers & cmdKey) ){
- PrSetError(iIOAbortErr);
- return TRUE;
- }
- }
- return FALSE;
- }
- /*
- * Routine to write asynchronously to the serial port, and run an
- * idle procedure while we wait. The idle routine may call PrSetError(),
- * so we check PrError() for abort each time. Kill pending serial port
- * IO if abort detected.
- */
- asyncwrite(s,idle)
- DPstorage s;
- ProcPtr idle;
- {
- IOParam *p = &(s->iopb.ioParam);
- PBWrite(p,TRUE); /* Issue ASYNC write. */
- do{
- (*idle)(); /* Idle til done. */
- if(PrError() != noErr){ /* Check for abort. */
- if(p->ioResult > 0){ /* More chars? */
- PBKillIO(p,FALSE); /* Stop output. */
- }
- longjmp(s->abortbuf,1); /* Get out. */
- }
- }while(p->ioResult > 0); /* Check for complete. */
- }
-